package edu.deltacollege.portal.portlets.emailpreview;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import javax.mail.Address;
import javax.mail.FetchProfile;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Legacy {@link EmailMessageDAO} implementation which reads all
 * message headers into memory for sorting by date and for finding
 * unread messages. Can be slightly faster than {@link SearchingEmailMessageDAO}
 * for small folders but an order of magnitude slower for large
 * (&gt;= 1000msg) folders.
 *
 */
public class LocalFilteringEmailMessageDAO implements EmailMessageDAO {
    
    private int maxUnreadMessages;
    private int maxTotalMessages;
    private MessageComparator comparator;
    
    private Log log;

    public LocalFilteringEmailMessageDAO () {
        this.log = LogFactory.getLog(LocalFilteringEmailMessageDAO.class);
        comparator = new MessageComparator(MessageComparator.ASC_ORDER);
    }

    public EmailMessageLookupResult getUnreadEmailMessages(Folder mailFolder) 
        throws MessagingException {
        
        Message[] allMessages = mailFolder.getMessages();
        int totalMessageCount = allMessages.length;

        if (log.isDebugEnabled()) {
            log.debug("Total message count: " + totalMessageCount);
        }

        long startTime = System.currentTimeMillis();
        
        // Fetch only necessary headers for each message
        FetchProfile profile = new FetchProfile();
        profile.add(FetchProfile.Item.ENVELOPE);
        profile.add(FetchProfile.Item.FLAGS);
        mailFolder.fetch(allMessages, profile);

        if (log.isDebugEnabled()) {
            log.debug("Time elapsed while fetching message headers:" +
                (System.currentTimeMillis() - startTime));
        }

        // Sort messages by sent date
        Arrays.sort(allMessages, comparator);

        Message[] messages = null;

        /*
         *  Determine if the total number of messages is more than the maximum number
         *  we need to inspect.
         */
        if (totalMessageCount > maxTotalMessages) {
            messages = new Message[maxTotalMessages];
            // Copy only the latest maxTotalMessages from the messages returned
            System.arraycopy(allMessages, (allMessages.length - maxTotalMessages),
                    messages, 0, maxTotalMessages);
        } else {
            // Inspect all messages returned
            messages = allMessages;
        }

        int inspectedMessageCount = messages.length;
        int unreadMessageCount = 0;
        List<EmailMessage> unreadEmails = new LinkedList<EmailMessage>();
        /*
         * Retrieving maxUnreadMessages and the unread message count.
         * Not using the getUnreadMessageCount() method since the method
         * also traverses all messages which we need to do anyway to retrieve
         * maxUnreadMessages.
         */
        for (int index = inspectedMessageCount - 1; index >= 0; index-- ) {

            Message currentMessage = messages[index];

            // Determine if the current message was read
            if (!currentMessage.isSet(Flags.Flag.SEEN)) {

                unreadMessageCount++;

                if (unreadMessageCount <= maxUnreadMessages) {

                    EmailMessage emailMessage = new EmailMessage();

                    // Set sender address
                    Address[] addresses = currentMessage.getFrom();
                    String sender = addresses[0].toString();
                    emailMessage.setSender(sender);

                    // Set subject and sent date
                    emailMessage.setSubject(currentMessage.getSubject());
                    emailMessage.setSentDate(currentMessage.getSentDate());

                    unreadEmails.add(emailMessage);
                }
            }
        }
        
        return new EmailMessageLookupResult(unreadEmails, inspectedMessageCount);
    }
    
    public int getTotalEmailMessageCount(Folder inbox) throws MessagingException {
        return inbox.getMessageCount();
    }
    
    /**
     * Supports all <code>AccountInfoDAO</code> impls/configs.
     */
    public boolean supports(AccountInfoDAO accountInfoDAO) {
        return true;
    }
    
    /**
     * The maximum number of unread messages to retrieve information for.
     *
     * @return The maximum number of unread messages to retrieve.
     */
    public int getMaxUnreadMessages() {
        return this.maxUnreadMessages;
    }

    /**
     * Sets the maximum number of unread messages to retrieve information for.
     *
     * @param maxUnreadMessages The maximum number of unread messages to retrieve.
     */
    public void setMaxUnreadMessages(int maxUnreadMessages) {
        this.maxUnreadMessages = maxUnreadMessages;
    }
    
    /**
     * Returns the maximum number of messages to inspect
     * in order to discover unread messages.
     *
     * @return Returns the maximum number of messages to inspect.
     */
    public int getMaxTotalMessages() {
        return this.maxTotalMessages;
    }

    /**
     * @param maxTotalMessages The maxTotalMessages to set.
     */
    public void setMaxTotalMessages(int maxTotalMessages) {
        this.maxTotalMessages = maxTotalMessages;
    }


}
